import json
import requests
import urllib.parse as urlparse
import sys

from coin.exchange.base.kr_rest.auth_base import AuthKey
from coin2.api_client.common import (SyncQueryer)
from enum import Enum

class Side(Enum):
  BUY = "Buy"
  SELL = "Sell"

class Type(Enum):
  LIMIT = "limit"
  MARKET = "market"

class KorbitAuth(requests.auth.AuthBase):
  def __init__(self, key):
    self._key = AuthKey.from_file(key)
    self.access_token = None
    self.refresh_token = None

  def __call__(self, req: requests.PreparedRequest):
    parsed = urlparse.urlparse(req.url)

    if parsed.path == "/v1/oauth2/access_token":
      req.prepare_body({
        'client_id': self._key.access_key,
        'client_secret': self._key.secret_key,
        'grant_type': 'client_credentials',
      }, None)

      return req

    assert self.access_token, "access_token empty, please call authentication before other api!"
    req.headers.update({'Authorization': "Bearer {}".format(self.access_token)})
    req.prepare_headers(req.headers)

    # print(req.headers)
    # print(req.body)
    # print(req.url)

    return req

class KorbitPrivateClient():
  def __init__(self, key_path: str, ip=None):
    self._auth = KorbitAuth(key_path)
    self._url = "https://api.korbit.co.kr"

    self._query = SyncQueryer(api_host=self._url, auth=self._auth, ip=ip)

  def authentication(self):
    method = "POST"
    path = "/v1/oauth2/access_token"

    response = self._query.query(method=method, path=path)
    json = response.json()

    self._auth.access_token = json['access_token']
    self._auth.refresh_token = json['refresh_token']

    return json

  def get_open_order(self, currency_pair: str = None):
    method = "GET"
    params = {
      "currency_pair": currency_pair,
    }
    path = "/v1/user/orders/open"

    response = self._query.query(method=method, path=path, params=params)
    return response.json()

  def cancel_order(self, currency_pair: str, id: str):
    assert currency_pair, "currency_pair must be not None and not empty!"
    assert id, "id must be not None and not empty!"

    method = "POST"
    data = {
      "currency_pair": currency_pair,
      "id": id,
    }
    path = "/v1/user/orders/cancel"

    response = self._query.query(method=method, path=path, data=data)
    return response.json()

  def submit_order(
    self,
    currency_pair: str,
    side: Side,
    type: Type,
    price: str = None,
    coin_amount: str = None,
    fiat_amount: str = None,
  ):
    assert currency_pair, "currency_pair must be not None and not empty!"
    assert side, "side must be not None!"
    assert type, "type must be not None!"

    method = "POST"
    data = {
      "currency_pair": currency_pair,
      "type": type.value,
      "price": price,
      "coin_amount": coin_amount,
      "fiat_amount": fiat_amount,
    }
    path = None
    if side == Side.BUY:
      path = "/v1/user/orders/buy"
    elif side == Side.SELL:
      path = "/v1/user/orders/sell"
    else:
      assert False, "side must be one of buy and sell!"

    response = self._query.query(method=method, path=path, data=data)
    return response.json()

# api doc url
# https://apidocs.korbit.co.kr/#first_section

if __name__ == "__main__":
  key_path = sys.argv[1]
  
  korbit = KorbitPrivateClient(key_path)
  info = korbit.authentication()
  info = korbit.get_open_order("btc_krw")
  # info = korbit.cancel_order('btc_krw', '1234567')
  # info = korbit.submit_order("btc_krw", Side.SELL, Type.LIMIT, "10000000", "0.00000001")
  print(json.dumps(info, indent=2))
